SpringSecurity底层原理和认证授权流程总结 |
您所在的位置:网站首页 › spring security 认证 › SpringSecurity底层原理和认证授权流程总结 |
安全框架(springsecurity、shiro等)主要分为两个部分: 认证:系统认为用户是否能登录授权:系统判断用户是否有权限去做某些事情 项目主要使用了:基于token的用户权限认证与授权维护用户和角色之间的关系 ![]() 注意在权限管理模块使用的JWT工具类是:但是这个工具类比较简单,我就拿common_utils中的JWT工具类来说明!!!!!! 认证过滤器 认证的过程是,先从登录请求中拿到对应的用户名和密码,对用户名密码进行登录校验(与数据库中比对),认证成功后执行successfulAuthentication方法,通过JWT工具类根据用户名生成token放在客户端的cookie中然后在redis中加入一个key,value,分别是用户名和权限列表认证失败则在响应中返回错误信息。 授权过滤器 当一个用户已经登录后,下次再访问服务器时,请求头中包含token信息, 服务器先从header中获取token,解析得到用户名,从redis中获取权限列表,由springsecurity给当前用户赋予权限*(哪些可以访问,哪些不能访问) 使用redisTemplate操作redis service_acl模块 UserDetailsServiceImpl类 因为在springsecurity包的核心配置类中要使用userDetailsService接口的实现类来操作数据库,查询用户的用户名密码等数据具体跨域的问题,看下面三个博客 面试官:你们项目中是怎么解决跨域的? SpringSecurity解决跨域问题 springboot解决跨域和集成springsecurity解决跨域 application.properties: # 服务端口 server.port=8222 # 服务名 spring.application.name=service-gateway # nacos服务地址 spring.cloud.nacos.discovery.server-addr=localhost:8848 #下面都是gateway配置 #使用服务发现路由(开启nacos服务发现) spring.cloud.gateway.discovery.locator.enabled=true #设置路由id spring.cloud.gateway.routes[0].id=service-acl #设置路由的uri lb://nacos注册服务名称 spring.cloud.gateway.routes[0].uri=lb://service-acl #设置路由断言,代理servicerId为auth-service的/auth/路径 spring.cloud.gateway.routes[0].predicates= Path=/*/acl/** #配置service-edu服务 spring.cloud.gateway.routes[1].id=service-edu spring.cloud.gateway.routes[1].uri=lb://service-edu spring.cloud.gateway.routes[1].predicates= Path=/eduservice/** #配置service-ucenter服务 spring.cloud.gateway.routes[2].id=service-ucenter spring.cloud.gateway.routes[2].uri=lb://service-ucenter spring.cloud.gateway.routes[2].predicates= Path=/ucenterservice/** #配置service-ucenter服务 spring.cloud.gateway.routes[3].id=service-cms spring.cloud.gateway.routes[3].uri=lb://service-cms spring.cloud.gateway.routes[3].predicates= Path=/cmsservice/** spring.cloud.gateway.routes[4].id=service-msm spring.cloud.gateway.routes[4].uri=lb://service-msm spring.cloud.gateway.routes[4].predicates= Path=/edumsm/** spring.cloud.gateway.routes[5].id=service-order spring.cloud.gateway.routes[5].uri=lb://service-order spring.cloud.gateway.routes[5].predicates= Path=/orderservice/** spring.cloud.gateway.routes[6].id=service-order spring.cloud.gateway.routes[6].uri=lb://service-order spring.cloud.gateway.routes[6].predicates= Path=/orderservice/** spring.cloud.gateway.routes[7].id=service-oss spring.cloud.gateway.routes[7].uri=lb://service-oss spring.cloud.gateway.routes[7].predicates= Path=/eduoss/** spring.cloud.gateway.routes[8].id=service-statistic spring.cloud.gateway.routes[8].uri=lb://service-statistic spring.cloud.gateway.routes[8].predicates= Path=/staservice/** spring.cloud.gateway.routes[9].id=service-vod spring.cloud.gateway.routes[9].uri=lb://service-vod spring.cloud.gateway.routes[9].predicates= Path=/eduvod/** spring.cloud.gateway.routes[10].id=service-edu spring.cloud.gateway.routes[10].uri=lb://service-edu spring.cloud.gateway.routes[10].predicates= Path=/eduservice/** gateway、nacos和权限管理模块的关系从上面配置文件看出,网关服务(api_gateway)对外暴露的端口是8222,也就是说前端的请求url是网关的ip+8222 网关接收到请求后,网关根据请求url的字符信息,去注册中心发现对应的服务(服务发现)。 前提是各个服务已经在nacos注册中心注册了 具体的nacos服务发现的规则(也就是怎么根据请求url找到对应的nacos注册中心的服务名)由上面的配置文件规定 和nginx的配置文件中配置的是一样的意思 springboot本质上是一个过滤器链,也就是说提供很多过滤器,这里只详细介绍项目中用到的过滤器。 UsernamePasswordAuthenticationFilter(登录过滤器) 项目中TokenLoginFilter继承了这个类* 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验 * * * @author qy * @since 2019-11-08 */ public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter { private AuthenticationManager authenticationManager; private TokenManager tokenManager; private RedisTemplate redisTemplate; public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) { this.authenticationManager = authenticationManager; this.tokenManager = tokenManager; this.redisTemplate = redisTemplate; this.setPostOnly(false); this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login","POST")); } @Override public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException { try { User user = new ObjectMapper().readValue(req.getInputStream(), User.class); return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList())); } catch (IOException e) { throw new RuntimeException(e); } } /** * 登录成功 * @param req * @param res * @param chain * @param auth * @throws IOException * @throws ServletException */ @Override protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException, ServletException { SecurityUser user = (SecurityUser) auth.getPrincipal(); String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername()); redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList()); ResponseUtil.out(res, R.ok().data("token", token)); } /** * 登录失败 * @param request * @param response * @param e * @throws IOException * @throws ServletException */ @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException { ResponseUtil.out(response, R.error()); } } 打开UsernamePasswordAuthenticationFilter源码,有下面这个方法 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { //1、先判断是不是post提交 if (this.postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } else { //2、从请求request获取用户名和密码 String username = this.obtainUsername(request); String password = this.obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); //3、查数据库,对用户名和密码进行校验 UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); this.setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } } 先判断是不是post提交从请求request获取用户名和密码查数据库,对用户名和密码进行校验 过滤器是如何被加载的? springboot帮我们完成了springsecurity的自动化配置 两个重要的接口: UserDetails 项目中SecurityUser实现了这个接口* 安全认证用户详情信息 * * * @author qy * @since 2019-11-08 */ @Data @Slf4j public class SecurityUser implements UserDetails { //当前登录用户 private transient User currentUserInfo; //当前权限 private List permissionValueList; public SecurityUser() { } public SecurityUser(User user) { if (user != null) { this.currentUserInfo = user; } } // 表示获取登录用户所有权限 @Override public Collection |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |